package yl.hs.bmipfull.utils;

import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import yl.hs.bmipfull.security.MD5;
import yl.hs.bmipfull.utils.datastate.ActiveDeviceType;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/*
 * MachineUtils
 * @category
 * @author 谢景广
 * @date 2022-05-09
 */
@Slf4j
public class MachineUtils {
    /**
     * 运行命令
     *
     * @param cmd  命令
     * @return 结果
     */
    private static String runCmd(String cmd) {
        Process process;
        Scanner sc = null;
        StringBuffer sb = new StringBuffer();
        try {
            process = Runtime.getRuntime().exec(cmd);
            process.getOutputStream().close();
            sc = new Scanner(process.getInputStream());
            int i = 0;
            while (sc.hasNextLine()) {
                i++;
                String str = sc.nextLine();
                str = str.replace("\r","").replace("\n","").replace(" ","");
                if(!Tl.isEmpty(str)){
                    sb.append(str);
                }
            }
            sc.close();
        } catch (Exception e) {
        } finally {
            if (sc != null) {
                try {
                    sc.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
    /**
     * 运行cmd命令
     *
     * @param cmd    命令
     * @param substr 关键字
     * @return 包含关键字的行数
     */
    private static String runCmd(String cmd, String substr) {
        Process process;
        Scanner sc = null;
        try {
            process = Runtime.getRuntime().exec(cmd);
            process.getOutputStream().close();
            sc = new Scanner(process.getInputStream());
            // log.info("sc.hasNextLine:{}", sc.hasNext());
            // log.info("sc.hasNextLine:{}", sc.hasNextLine());
            while (sc.hasNextLine()) {
                String str = sc.nextLine();
                // log.info("command返回信息：{}", str);
                if (!Tl.isEmpty(str)) {
                    str = str.trim();
                    if (str != null && str.startsWith(substr)) {
                        // log.info("command 提取信息：{}", str);
                        return str.trim();
                    }
                }
            }
            sc.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sc != null) {
                try {
                    sc.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 获取mac地址
     *
     * @return mac 列表
     */
    public static String getMacs() {
        List<String> macList = getMacList();
        if (macList != null && macList.size() > 0) {
            return String.join(",",macList.toArray(new String[macList.size()]));
        }
        return null;
    }

    /**
     * 获取mac地址
     *
     * @return mac 列表
     */
    private static List<String> getMacList() {
        List<String> list = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        try {
            java.util.Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
            while (en.hasMoreElements()) {
                NetworkInterface iface = en.nextElement();
                List<InterfaceAddress> addrs = iface.getInterfaceAddresses();
                for (InterfaceAddress addr : addrs) {
                    InetAddress ip = addr.getAddress();
                    if (ip.isLinkLocalAddress()) {//本地的不要
                        continue;
                    }
                    NetworkInterface network = NetworkInterface.getByInetAddress(ip);
                    if (network == null) {
                        continue;
                    }

                    // 先这做，后期优化
                    // TODO
                    if (!Tl.isEmpty(network.getName()) && network.getName().startsWith("lo")) {
                        // lo 为本地回环地址，eth0 和 eth4 为 VMware 创建的虚拟地址
                        continue;
                    }
                    if (!Tl.isEmpty(network.getName()) && network.getName().startsWith("docker")) {
                        // docker内网地址排除
                        continue;
                    }
                    if (!Tl.isEmpty(network.getName()) && (network.getName().startsWith("cni") || network.getName().startsWith("flannel"))) {
                        // docker内网地址排除
                        continue;
                    }
                    if (!Tl.isEmpty(network.getName()) && network.getName().startsWith("br")) {
                        // 排除桥接网卡
                        continue;
                    }



                    byte[] mac = network.getHardwareAddress();
                    if (mac == null) {
                        continue;
                    }

                    sb.delete(0, sb.length());
                    for (int i = 0; i < mac.length; i++) {
                        sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
                    }
                    if (!list.contains(sb.toString())) {
                        list.add(sb.toString());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
    /**
     * 获取cpu序列号
     *
     * @return 序列号
     */
    private static String getCPUSerialNumber() {
        String sysName = System.getProperty("os.name");
        // log.info("系统名称：{}", sysName);
        if (sysName.contains("Windows")) {//win
            String str = runCmd("wmic cpu get ProcessorId");
            return str.replace("ProcessorId","");
        } else if (sysName.contains("Linux")) {
            String str = getLinuxCpuId("dmidecode -t processor | grep 'ID'", "ID", ":");
            log.info("【Linux】返回信息：{}", str);
            if (StrUtil.isNotBlank(str)) {
                return str.replace("UUID:","").trim();
            }
        } else if (sysName.contains("Mac")) {
            String str = runCmd("system_profiler SPHardwareDataType", "Serial Number");
            if (str != null) {
                return str.substring(str.indexOf(":") + 1).trim();
            }
        }
        return "";
    }

    /**
     * 获取linux系统CPU序列
     */
    public static String getLinuxCpuId(String cmd, String record, String symbol){
        String execResult = RuntimeUtil.execForStr(cmd);
        String[] infos = execResult.split("\n");
        for (String info : infos) {
            info = info.trim();
            if (info.indexOf(record) != -1) {
                info.replace(" ", "");
                String[] sn = info.split(symbol);
                return sn[1];
            }
        }
        return null;
    }

    /**
     * 获取硬盘序列号
     *
     * @return 硬盘序列号
     */
    private static String getHardDiskSerialNumber() {
        String sysName = System.getProperty("os.name");
        if (sysName.contains("Windows")) {//win
            String str = runCmd("wmic path win32_physicalmedia get serialnumber");
            return str.replace("SerialNumber","");
        } else if (sysName.contains("Linux")) {
            // String str = runCmd("dmidecode |grep -A16 \"System Information$\"", "Serial Number");
            String str = runCmd("dmidecode | grep \"Serial Number\"", "Serial Number");
            // log.info("getHardDiskSerialNumber1返回信息：{}", str);
            if (!Tl.isEmpty(str) && ": Not Specified".equals(str)) {
                return str.substring(str.indexOf(":") + 1).trim();
            } else {
                // str = runCmd("dmidecode |grep -A16 \"System Information$\"", "UUID");
                str = runCmd("dmidecode | grep \"UUID\"", "UUID");
                // log.info("getHardDiskSerialNumber2返回信息：{}", str);
                if (!Tl.isEmpty(str)) {
                    return str.substring(str.indexOf(":") + 1).trim();
                }
            }
        } else if (sysName.contains("Mac")) {
            String str = runCmd("system_profiler SPStorageDataType", "Volume UUID");
            if (str != null) {
                return str.substring(str.indexOf(":") + 1).trim();
            }
        }
        return "";
    }

    /**
     * 获取当前运行进程
     *
     * @author sun
     * @return java.lang.String
     */
    public static String getRuntimeProcess() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        return runtimeMXBean.getName();
    }


    /**
     * 生成机器码
     *
     * @return 机器码
     */
    public static String makeMachineCode() {
        //String macAddress = getMacs();
        String cpuSerialNumber = getCPUSerialNumber();
        String hardDiskSerialNumber = getHardDiskSerialNumber();
        // 组合字符串
        StringBuffer sb = new StringBuffer();
        //sb.append(macAddress);
        //sb.append(HsApp.getSystemSet(CK.Cloud_EnterpriseSN));
        sb.append(cpuSerialNumber);
        sb.append(hardDiskSerialNumber);
        //sb.append(HsApp.getSystemSet(CK.Cloud_ServerSN);
        return MD5.getMD5(sb.toString());
    }
    /**
     * 生成机器码
     * @param type 系统类型
     * @return 机器码
     */
    public static String makeMachineCode(ActiveDeviceType type) {
        String cpuSerialNumber = getCPUSerialNumber();
        String hardDiskSerialNumber = getHardDiskSerialNumber();
        // 组合字符串
        StringBuffer sb = new StringBuffer();
        sb.append(cpuSerialNumber);
        sb.append(hardDiskSerialNumber);
        sb.append(type.dataCode);
        return MD5.getMD5(sb.toString());
    }
}
